﻿using System.Collections.Generic;
using UnityEngine;

public class CameraLevel1 : CameraLevel
{

    [Header("进入关底配置")]
    [Tooltip("进入关底后强制卷轴速度")]
    public float bossForceSpeed = 3f;
    [Tooltip("是否开始进入关底")]
    private bool bossForce = false;


    [Header("关卡完成配置")]
    [Tooltip("Boss爆炸效果预制件")]
    public GameObject bossBoomPrefab;
    [Tooltip("Boss每次爆炸的间隔时间")]
    public float bossBoomIntervalTime = 0.5f;
    [Tooltip("Boss爆炸后显示的通道")]
    public GameObject bossBoomEffectObject;
    [Tooltip("Boss是否已爆炸")]
    private bool bossBoom = false;
    [Tooltip("Boss开始爆炸的时间")]
    private float bossBoomTime;
    [Tooltip("Boss分段爆炸，上一次爆炸的序号")]
    private int bossBoomLastIndex = -1;
    [Tooltip("过关后开始角色的通关动作脚本")]
    public SeqAction playerScenario = new() { beginWaitTime = 0f, };
    [Tooltip("过关后消失的墙壁，与过关脚本配合使用")]
    public GameObject[] destroyWhenBossBoom;

    private bool startPressDown;

    [Tooltip("剧本动作")]
    public SeqAction scenarioWait = new() { beginWaitTime = 2f };

    private void Awake()
    {
        base.Init();
    }
    private void Start()
    {
        beginPerformanceAction.ReStart();
        playerBornAction.ReStart();
    }
    private void Update()
    {

        startPressDown = startPressDown || Input.GetButtonDown("Start");
        UpdatePause();
    }
    private void FixedUpdate()
    {
        UpdateBeginPerformance();
        UpdateFollowPlayer();
        UpdateBossForceMove();
        UpdateCheckMaxRight();
        UpdateBossBoom();
    }
    private void UpdatePause()
    {
        if (startPressDown)
        {
            if (Time.timeScale == 0f)
            {
                Time.timeScale = 1f;
                UnPause();
            }
            else
            {
                Time.timeScale = 0f;
                Pause();
            }
            startPressDown = false;
        }
    }
    private void UpdateFollowPlayer()
    {
        IEnumerable<Vector3> playersPosition = GameObject.FindGameObjectsWithTag("Player")
            .Filter((GameObject player) =>
            {
                if (player.TryGetComponent(out Player p))
                {
                    return p.GetLife() > 0;
                }
                else
                {
                    return true;
                }
            })
            .Transform((GameObject player) =>
            {
                return player.transform.position;
            });

        Vector3 minPosition = playersPosition.Min((Vector3 p1, Vector3 p2) =>
        {
            float v = p1.x - p2.x;
            return Mathf.Approximately(v, 0.0f) ? 0 : (v < 0 ? -1 : 1);
        });
        Vector3 maxPosition = playersPosition.Max((Vector3 p1, Vector3 p2) =>
        {
            float v = p1.x - p2.x;
            return Mathf.Approximately(v, 0.0f) ? 0 : (v < 0 ? -1 : 1);
        });
        Vector3 playersCenterPosition = minPosition + (maxPosition - minPosition) / 2f;

        Vector3 cameraPosition = transform.position;
        if (playersCenterPosition.x > cameraPosition.x)
        {
            cameraPosition.x = playersCenterPosition.x;
        }
        transform.position = cameraPosition;
    }
    private void UpdateCheckMaxRight()
    {
        Vector3 cameraPosition = transform.position;
        cameraPosition.x = Mathf.Clamp(cameraPosition.x, minRight, maxRight);
        transform.position = cameraPosition;
    }

    private void UpdateBossBoom()
    {
        if (bossBoom)
        {
            bossBoomEffectObject.SetActive(true);
            float dt = Time.time - bossBoomTime;
            int index = Mathf.CeilToInt(dt / bossBoomIntervalTime);
            bool newIndex = false;
            if (bossBoomLastIndex != index)
            {
                newIndex = true;
                bossBoomLastIndex = index;
            }
            if (index < 7)
            {
                SpriteRenderer sr = bossBoomEffectObject.GetComponent<SpriteRenderer>();
                Vector2 size = sr.size;
                size.x = index + 1;
                sr.size = size;
                if (newIndex && bossBoomPrefab != null)
                {
                    Vector2 position = bossBoomEffectObject.transform.position;
                    position += Vector2.right * index + Vector2.up * (Random.Range(-1f, 1f));
                    Instantiate(bossBoomPrefab, position, Quaternion.identity);
                }
            }
            else
            {
                //这里使用SeqAction是为了只运行一次
                playerScenario.Update((SeqAction seq) =>
                {
                    destroyWhenBossBoom.Action((GameObject o) =>
                    {
                        o.SetActive(false);
                    });

                    GameObject.FindGameObjectsWithTag("Player").Action((GameObject playerObject) =>
                    {
                        if (playerObject.TryGetComponent(out Player player))
                        {
                            player.RunScenario(this.ScenarioBossDie);
                        }
                    });
                    playerScenario.done = true;
                    Constant.Sounds.Victory.PlayOneShot();

                });

                bool playerInsideOfViewport = false;
                GameObject.FindGameObjectsWithTag("Player").Action((GameObject playerObject) =>
                {
                    if (!playerInsideOfViewport && playerObject.TryGetComponent(out Player player))
                    {
                        Vector3 position = player.transform.position;
                        playerInsideOfViewport = player.GetLife() > 0 && Utility.InCameraViewport(gameObject.GetComponent<Camera>(), position, 2f / 16f);
                    }
                });
                if (!playerInsideOfViewport)
                {
                    ScenceFinshed();
                }
            }
        }
    }

    public void BossBoom()
    {
        if (!bossBoom)
        {
            backgroundSound.Stop();
            bossBoom = true;
            bossBoomTime = Time.time;
            GameObject.FindGameObjectsWithTag("Boss").Action((GameObject o) =>
            {
                if (o.TryGetComponent(out EnemyBase enemy))
                {
                    enemy.Die();
                }
            });
            GameObject.FindGameObjectsWithTag("敌人").Action((GameObject o) =>
            {
                if (o.TryGetComponent(out EnemyBase enemy))
                {
                    enemy.Die();
                }
            });
            Constant.Sounds.BossDeath.PlayOneShot();
        }
    }

    private void UpdateBossForceMove()
    {
        if (bossForce)
        {
            Vector3 position = transform.position;
            if (position.x < maxRight)
            {
                position.x += bossForceSpeed * Time.deltaTime;
                transform.position = position;
            }
        }
    }
    public void StartBoss()
    {
        if (!bossForce)
        {
            bossForce = true;
            Constant.Sounds.BossAlarm.PlayOneShot();
            GameObject.FindGameObjectsWithTag("Boss").Action((GameObject o) =>
            {
                if (o.TryGetComponent(out EnemyBase enemy))
                {
                    enemy.Run();
                }
            });
        }
    }

    public override int GetLevelNo()
    {
        return 1;
    }

    private Player.ScenarioAction ScenarioBossDie(PlayerContext context){
        Player.ScenarioAction ret=new();
        ret.SetFloat(Player.KeyMapKey.Horizontal.ToString(), 0f);
        ret.SetBool(Player.KeyMapKey.Fire.ToString(), false);
        ret.SetBool(Player.KeyMapKey.Jump.ToString(), false);
        scenarioWait.Update((SeqAction seq) =>
        {
            ret.SetFloat(Player.KeyMapKey.Horizontal.ToString(), 1f);
            Vector2 position = context.GetBodyPartPosition(Person.BodyPart.Body);
            RaycastHit2D hit = Physics2D.Raycast(position, Vector2.right, 0.625f, Constant.LayersMask.WallLayer);
            if (hit) 
            {
                bool onGround=context.IsOnGround();
                if(onGround){
                    ret.SetBool(Player.KeyMapKey.Jump.ToString(), true);
                }
            }
        });
        return ret;
    }
}
